package com.echovin.esb.gateway.filter;

import com.echovin.esb.gateway.constants.ErrorCode;
import com.echovin.esb.gateway.constants.OrderConstants;
import com.echovin.esb.gateway.exception.OpenException;
import com.echovin.esb.gateway.locator.GatewayParameterValidateResourceLocator;
import com.echovin.esb.gateway.model.TwoTuple;
import com.echovin.esb.gateway.parameter.SchemaValidator;
import com.echovin.esb.gateway.parameter.impl.JsonSchemaValidator;
import com.echovin.esb.gateway.parameter.impl.WSDLXMLSchemaValidator;
import com.echovin.esb.gateway.parameter.impl.XMLSchemaValidator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.nio.charset.StandardCharsets;


/**
 * 参数校验全局过滤器
 */
@Slf4j
@Component
public class ParameterValidateGlobalFilter implements GlobalFilter, Ordered {
    public static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";
    @Autowired
    GatewayParameterValidateResourceLocator validateResourceLocator;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 读取cacheBodyFilter中缓存中的body
        String cachedBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);
//        Flux<DataBuffer> cachedBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);
        if (cachedBody == null) {
            return chain.filter(exchange);
        }
        ServerHttpRequest request = exchange.getRequest();
        URI requestUri = request.getURI();
        HttpHeaders headers = request.getHeaders();
        MediaType contentType = headers.getContentType();
        // 只处理 application/xml、application/json 格式参数
        SchemaValidator validator;
        String url = request.getURI().getPath();
        if (!StringUtils.isEmpty(headers.getFirst("SOAPAction"))) {
            // 说明是webservice，对其动作进行参数校验
            url = headers.getFirst("SOAPAction");
            validator = new WSDLXMLSchemaValidator();
        } else {
            if (MediaType.APPLICATION_JSON.equals(contentType)) {
                validator = new JsonSchemaValidator(validateResourceLocator);
            } else if (MediaType.APPLICATION_XML.equals(contentType)) {
                validator = new XMLSchemaValidator(validateResourceLocator);
            } else {
                return chain.filter(exchange);
            }
        }

        // 解析body
//        String bodyStr = resolveBodyFromRequest(cachedBody);
        // 根据scheme校验body
        TwoTuple<Boolean, String> twoTuple = validator.schemaValidator(url, cachedBody);
        if (twoTuple != null && !twoTuple.first) {
            throw new OpenException(ErrorCode.PARAMWTER_ERROR.getCode(),twoTuple.second);
        }

        return chain.filter(exchange);
    }


    @Override
    public int getOrder() {
        return OrderConstants.PARAMTER_CHECK;
    }

    /**
     * 获取请求体中的字符串内容
     *
     * @param body
     * @return
     */
    private String resolveBodyFromRequest(Flux<DataBuffer> body) {
        StringBuilder sb = new StringBuilder();
        body.subscribe(buffer -> {
            byte[] bytes = new byte[buffer.readableByteCount()];
            buffer.read(bytes);
            DataBufferUtils.release(buffer);
            String bodyString = new String(bytes, StandardCharsets.UTF_8);
            sb.append(bodyString);
        });
        return sb.toString();

    }

}
